﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cjc.Data.Mapping;
using System.Linq.Expressions;
using System.Reflection;

namespace SampleDomainModel
{
	public class QueryContext : QueryContextBase
	{
		private IDataProviderSpecification provider;
		private Type contextType;
		private IMappingContextInfo mappingContextInfo;
		private ExpressionTranslator expressionTranslator;

		public QueryContext( IDataProviderSpecification provider )
		{
			this.provider = provider;

			this.contextType = ( provider.MockingContext != null )
				? provider.MockingContext.GetType()
				: Assembly.Load( provider.ContextAssembly ).GetType( provider.ContextType );

			this.mappingContextInfo = this.contextType.GetMappingContextInfo();
			this.expressionTranslator = this.mappingContextInfo.CreateExpressionTranslator();
		}

		public override LambdaExpression TranslateToLambda( Expression expression )
		{
			return expressionTranslator.TranslateToLambda( expression );
		}

		public override IEnumerable<T> GetEnumerable<T>( LambdaExpression expression )
		{
			var context = GetContext();
			var invoke = Expression.Invoke( expression, Expression.Constant( context, contextType ) );

			return mappingContextInfo.GetQueryProvider( context ).CreateQuery<T>(
				mappingContextInfo.MustInlineInvokes ? invoke.InlineInvokes() : invoke );
		}

		public override TResult Execute<TResult>( LambdaExpression expression )
		{
			var context = GetContext();
			var invoke = Expression.Invoke( expression, Expression.Constant( context, contextType ) );

			return mappingContextInfo.GetQueryProvider( context ).Execute<TResult>(
				mappingContextInfo.MustInlineInvokes ? invoke.InlineInvokes() : invoke );
		}

		private object GetContext()
		{
			return provider.MockingContext
				?? Activator.CreateInstance( contextType );
		}
	}
}
